#ifndef __NET_UTILS_H__
#define __NET_UTILS_H__

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>

#include <string>

class NetUtils
{
public:
    static int set_tcp_no_delay(int fd, bool no_delay = true) {
        int enable = no_delay ? 1 : 0;
        return setsockopt(
            fd, 
            IPPROTO_TCP, 
            TCP_NODELAY, 
            &enable, 
            sizeof(enable)
        );
    }

    static int set_socket_block(int fd) {
        auto flag = fcntl(fd, F_GETFL, 0);
        if (flag == -1) {
            return -1;
        }
        flag &= ~O_NONBLOCK;
        return fcntl(fd, F_SETFL, flag);
    }

    static int set_socket_unblock(int fd) {
        auto flag = fcntl(fd, F_GETFL, 0);
        if (flag == -1) {
            return -1;
        }
        return fcntl(fd, F_SETFL, flag | O_NONBLOCK);
    }

    static int set_socket_reuseaddr(int fd, bool on = true) {
        int opt = on ? 1 : 0;
        return setsockopt(
            fd, 
            SOL_SOCKET, 
            SO_REUSEADDR, 
            (const void*)&opt, 
            sizeof(opt)
        );
    }

    static int bind_and_listen(int fd, const std::string& host, int port, int backlog)
    {
    	struct sockaddr_in saddr;
    	saddr.sin_family = AF_INET;
    	saddr.sin_port   = htons(port);
	    if (host.length() == 0) {
        	saddr.sin_addr.s_addr = INADDR_ANY;
	    } else {
        	saddr.sin_addr.s_addr = htonl(inet_addr(host.c_str()));
	    }
	    int ret = bind(fd, (struct sockaddr*)&saddr, sizeof(saddr));		
	    if (ret == -1) {
	    	return -1;
	    }
	    ret = listen(fd, backlog);
	    if (ret == -1) {
	    	return -1;
	    }
	    return 0;
    }
};

#endif
